/*
 * @Description: 
 * @Version: 1.0
 * @Autor: ziwei
 * @Date: 2021-05-16 09:56:34
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2021-07-18 22:58:18
 */
import { isObject, isReservedTag } from "../utils"
//看两个节点是不是相同节点 就看是不是tag和key都一样
// vue2就是有一个性能问题，递归比对 || vue3 blockTree 收集动态节点，线性比对 性能更高
export function  isSameVnode(newVnode,oldVnode) {
  return (newVnode.tag === oldVnode.tag) && (newVnode.key == oldVnode.key)
}

//2.组件初始化的时候 会做一个合并mergeOptions
//3.内部会对模板进行编译操作_c() 还会判断Ctor 如果是对象会调用VUe.extend,所有的组件都是Vue.exteng方法来实现的(componentOpt)
//4.创建组件的真是节点

function createComponent(vm,tag,data,children,key,Ctor) {
  if(isObject(Ctor)){//组件的定义一定是通过Vue.extend进行包裹的
    Ctor = vm.$options._base.extend(Ctor)
  }
  data.hook = {
    //组件的生命周期
    init(vnode){//vnode.componentInstance.$el -> 对应组件渲染完毕后的结果
      let child = vnode.componentInstance = new Ctor({});//我想获取组件的真实实例 创建子组件的实例保存起来
      child.$mount();//所以组件在走挂在的时候 vm.$el为null

      //mount挂在完毕后 会产生一个真实节点，这个节点在vm.$el上-》对应的就是组件的真实内容
    },
    //组件的更新流程
    prepatch(){

    },
    postpatch(){
      
    }
  }
  //每个组件 默认的名字内部都会给你拼接一下 vue-component-1-my-button(数组是一个序号 每new一个+1)
  let componentOptions = vnode(vm,tag,data,undefined,key,undefined,{Ctor,children,tag});
  return componentOptions;//componentOptions(非常重要包含了Ctor children propsData  listeners等) 存放了一个重要的属性Ctor
}
//tag 有可能是组件 createElement({}) createElement(function(){})
export function createElement(vm, tag, data = {}, ...children) { // 返回虚拟节点 _c('',{}....)

  // 如果区分是组件还是元素节点？  这个时候是虚拟节点 还没有nodeType; 看看是不是普通标签 
  //这里不考虑复杂的就是string类型
  if (!isReservedTag(tag)) {
    //Ctor 是组件最重要的属性
    //有可能是对象
    let Ctor = vm.$options.components[tag]; // 组件的初始化 就是new 组件的构造函数 tag标签
    //创建组件的虚拟节点  如果是组件要拿到组件的定义
    return createComponent(vm, tag, data, children, data.key, Ctor);
  }

  return vnode(vm, tag, data, children, data.key, undefined)
}

export function createText(vm, text) { // 返回虚拟节点
  return vnode(vm, undefined, undefined, undefined, undefined, text)
}

//options 可能是对象(自己定义的组件) 所以不放Ctor
function vnode(vm,tag,data,children,key,text,options) {
  return {
    vm, tag, data, children,key,text,componentOptions:options
  }
}
//vnode其实就是一个对象用来描述节点的，和ast长的很像？
//ast描述语法的，它并没有用户自己的逻辑，只有语法解析出来的内容
//vnode它是（用户自己）描述dom结构的 可以自己去扩展属性 